package com.higgins.lawapp.server;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.higgins.lawapp.client.settings.dataItemModel.DataItemDTO;
import com.higgins.lawapp.client.settings.dataItemModel.DataItemLevelDTO;
import com.higgins.lawapp.client.settings.dataModel.DataSourceLevelDTO;
import com.higgins.lawapp.client.settings.dataModel.DataSourceObjectDTO;
import com.higgins.lawapp.server.dataItemModel.DataItem;
import com.higgins.lawapp.server.dataItemModel.DataItemLevel;
import com.higgins.lawapp.server.dataModel.DataSourceLevel;
import com.higgins.lawapp.server.dataModel.DataSourceObject;

public class InternetManager {
	private int limitCollected = 50;
	private String fileURLReplacement = null;
	private BufferedReader in = null;
	private List<DataItem> dataItemsCollected = new ArrayList<DataItem>();
	private Iterator<DataSourceObject> iterator = null;
	private DataSourceObject currentDataSourceObject = null;
	private String elementEnd;
	private String elementStart;
	private String inputLine;
    private ArrayList<String> startText = new ArrayList<String>();
    private ArrayList<String> endText = new ArrayList<String>();
    private ArrayList<Boolean> urlList = new ArrayList<Boolean>();
    private Integer urlIndex = null;
    private Integer concatIndex = null;
    private int urlCount = 0;
	private Boolean urlOne = false;
	private Boolean urlTwo = false;
	private Boolean concatOne = false;
	private Boolean concatTwo = false;
	private Boolean containsEndElement=false;
	private DataItem dataItem=null;
	private String itemOne = null;
	private String itemTwo = null;
    private Integer fieldCount=null;
    private Integer maxField = null;
    private String fieldStartText = null;
    private String fieldEndText = null;
	private Integer start = null;
	private String afterStartText = null;
	private Integer end = null;

	/*
	public List<DataItem> executeDataItemCollectionFromParent(DataItem parent, DataSourceLevel dataSourceLevel, String urlFilename, Boolean concat)	{
		urlFilename = parent.getFirstUrl();
		// THIS METHOD RETURNS A LEVEL IRRESPECTIVE OF WHETHER ITS ACTUALLY AN INSTANCE
		List<DataItem> dataItems = executeDataItemCollection(dataSourceLevel, urlFilename, concat);

		// THEREFORE IT'S NECESSARY TO CONVERT THE LEVEL TO AN INSTANCE WHERE NECESSARY
		return dataItem;
	}		*/
	

	public List<DataItem> executeDataItemCollection(DataSourceLevel dataSourceLevel, String urlFilename, Boolean concat, 
			String fileURLReplacement)	throws NoDataSourceObjectsException, ScreenScrapeFailedException{
		this.fileURLReplacement = fileURLReplacement;
		return executeDataItemCollection(dataSourceLevel, urlFilename, concat);
	}
	
	
	@SuppressWarnings("unused")
	public List<DataItem> executeDataItemCollection(DataSourceLevel dataSourceLevel, String urlFilename, Boolean concat) throws NoDataSourceObjectsException, ScreenScrapeFailedException	{
		dataItemsCollected = new ArrayList<DataItem>();
		iterator = getDataSourceObjectsIterator(dataSourceLevel);
		currentDataSourceObject = iterator.next();
		try	{
			getInternetReader(dataSourceLevel, urlFilename, concat);
	        processLabels();
	        processElements();
	        in.close();		
		} catch (NoElementException e)	{
			System.out.println("NoElementException " + e.toString());
		} catch (NotMarkedForExecutionException e)	{
			System.out.println("DataSourceObject not marked for collection " + e.toString());
		} catch (IOException e)	{
			System.out.println("IO Exception " + e.toString());
		} catch (Exception e)	{
			System.out.println("Screen Scrape Failed!!" + e.toString());
			throw new ScreenScrapeFailedException();
		}	
		return dataItemsCollected;		
	}	
	
	
	// THIS METHOD RETURNS A LEVEL IRRESPECTIVE OF WHETHER ITS ACTUALLY AN INSTANCE
//	DataItemLevel dataItemLevel = new DataItemLevel();		
	// add check for null key name and replace with name
//	dataItemLevel.setDataItemLevelName(dataSourceLevel.getDataSourceName());

	private void processLabels()	throws IOException {
        inputLine = in.readLine();
        while (currentDataSourceObject.getDataSourceType().equals("Label"))	{
	        inputLine = label(in, inputLine, currentDataSourceObject.getDataSourceLabel(), currentDataSourceObject.getDataSourceNumber());
	        currentDataSourceObject = iterator.next();
        }
	}
	
	private void processElements()	throws IOException, NoElementException {
		if (currentDataSourceObject.getDataSourceType().equals("Element"))	{
			// Record End Tag
			elementStart = currentDataSourceObject.getDataSourceStart();
			elementEnd = currentDataSourceObject.getDataSourceEnd();
			
    		while (inputLine!=null && !containsEndElement)	{
    			initialiseElementVariables();
		        retrieveListOfElementFields();
		        checkForUrlFields();
		        findStartOfElement();
	    		
	    		// Run a loop until you reach the end of the element
	    		while (!containsEndElement && inputLine!=null)	{
	    			processElement();
	    		}
			}
		} 	
		containsEndElement = false;
	}
	
	private void processElement() throws IOException	{
		// Check for each Field
        fieldCount=0;
        maxField = startText.size();
        fieldStartText = startText.get(fieldCount);
        fieldEndText = endText.get(fieldCount);
        
        // Change this to while
		if (inputLine.contains(fieldStartText))	{
			processFirstField();
			processSecondField();
		} else if (inputLine.contains(elementEnd))
			containsEndElement = true;
		else
	        inputLine = in.readLine();
		
	}
	
	private void initialiseElementVariables()	{
        startText = new ArrayList<String>();
        endText = new ArrayList<String>();
        urlList = new ArrayList<Boolean>();
        urlIndex = null;
        concatIndex = null;
        urlCount = 0;
		urlOne = false;
		urlTwo = false;
		concatOne = false;
		concatTwo = false;
	}
	private void retrieveListOfElementFields()	{
        while (iterator.hasNext())	{
	        currentDataSourceObject = iterator.next();
	        if (currentDataSourceObject.getDataSourceType().equals("Field"))	{
		        startText.add(currentDataSourceObject.getDataSourceStart());
		        endText.add(currentDataSourceObject.getDataSourceEnd());
		        urlList.add(currentDataSourceObject.getURL());
		        if (currentDataSourceObject.getURL())
		        	urlIndex = urlCount;
		        if (currentDataSourceObject.getConcat())
		        	concatIndex = urlCount;
	        }
	        urlCount++;
        }
	}
	private void checkForUrlFields()	{
        if (urlIndex!=null)	{
	        switch(urlIndex)	{
	        case 0:	
	        	urlOne = true;
	        	break;
	        case 1:
	        	urlTwo = true;
	        	break;
	        }
        }
        
        if (concatIndex!=null)	{
	        switch(concatIndex)	{
	        case 0:	
	        	concatOne = true;
	        	break;
	        case 1:
	        	concatTwo = true;
	        	break;
	        }	
        }
	}
	private void findStartOfElement() throws IOException	{
        // Run through lines until you reach the start
		while (!inputLine.contains(elementStart) && inputLine!=null  && !containsEndElement)	{
			if (inputLine.contains(elementEnd))
				containsEndElement = true;
			else
    	        inputLine = in.readLine();
    	}
	}	

	private void processFirstField()	{
		start = inputLine.indexOf(fieldStartText);
		afterStartText = inputLine.substring(start+fieldStartText.length());
		end = afterStartText.indexOf(fieldEndText);
		if ((start>=0) && (end >= 0))	{
//        			List<DataItem> dataItems = dataItemsCollected;
			if (dataItemsCollected.size() < limitCollected)	{
        		dataItem = new DataItem();
				itemOne = inputLine.substring(start + fieldStartText.length(), (start + fieldStartText.length() + end));
				if (itemOne.equals(""))
					itemOne = "Empty";
        		if ((!itemOne.contains("MyLocker")) && (!itemOne.contains("Empty")))	{
	        		dataItem.setDataItemOne(itemOne);
	        		dataItem.setURLOne(urlOne);
	        		dataItem.setConcatOne(concatOne);
	        		dataItemsCollected.add(dataItem);
        		}
			}
    		// NEWLY ADDED!!!!
    		inputLine = inputLine.substring(start + fieldStartText.length() + end + fieldEndText.length());
		}
	}
	private void processSecondField() throws IOException {
		boolean secondFieldFound = false;
		fieldCount++;
        fieldStartText = startText.get(fieldCount);
        fieldEndText = endText.get(fieldCount);
        while (!secondFieldFound && !containsEndElement)	{
			if (inputLine.contains(fieldStartText))	{
	    		start = inputLine.indexOf(fieldStartText);
	    		afterStartText = inputLine.substring(start+fieldStartText.length());
	    		end = afterStartText.indexOf(fieldEndText);
	    		if ((start>=0) && (end >= 0))	{
	//        			List<DataItem> dataItems = dataItemLevel.getDataItems();
	    			if (dataItemsCollected.size() < limitCollected)		{
	    				if (dataItem!=null)	{
	        				itemTwo = inputLine.substring(start + fieldStartText.length(), (start + fieldStartText.length() + end));
		        			secondFieldFound = true;
			        		if ((!itemTwo.contains("MyLocker")) && (!itemTwo.contains("Select")))	{
				        		dataItem.setDataItemTwo(itemTwo);
				        		dataItem.setURLTwo(urlTwo);
				        		dataItem.setConcatTwo(concatTwo);
				        		System.out.println(dataItem.getDataItemOne() + "; " + dataItem.getDataItemTwo());
	        				}
	    				}
	    			}
	        		inputLine = inputLine.substring(start + fieldStartText.length() + end + fieldEndText.length());
	    		} else if (end<0)
	    	        inputLine = in.readLine();
	    	} 
				
			if (containsElementEndBeforeAnyFieldStartText())
				containsEndElement = true;
			else if (!containsFieldStartTextBeforeAnyElementEnd())
		        inputLine = in.readLine();
        }
	}

	private boolean containsFieldStartTextBeforeAnyElementEnd()	{
		if (!inputLine.contains(fieldStartText))
			return false;
		if (inputLine.contains(elementEnd))	{
			Integer fieldLocation = inputLine.indexOf(fieldStartText);
			Integer elementEndLocation = inputLine.indexOf(elementEnd);
			if (fieldLocation < elementEndLocation)
				return true;
			else
				return false;
		} else
			return false;
	}
	
	private boolean containsElementEndBeforeAnyFieldStartText()	{
		if (!inputLine.contains(elementEnd))
			return false;
		if (inputLine.contains(fieldStartText))	{
			Integer fieldLocation = inputLine.indexOf(fieldStartText);
			Integer elementEndLocation = inputLine.indexOf(elementEnd);
			if (fieldLocation > elementEndLocation)
				return true;
			else
				return false;
		} else
			return false;
	}
	
	public String label(BufferedReader in, String inputLine, String label, Integer number)	{
		int count = 0;
		while (count < number)	{
			try	{
				while (!inputLine.contains(label) && inputLine!=null)	{
			        inputLine = in.readLine();
				}
				inputLine = inputLine.substring(inputLine.indexOf(label) + label.length());
			}	catch (Exception e)	{ 		}
			count++;
		}
		return inputLine;
	}
	
	private Iterator<DataSourceObject> getDataSourceObjectsIterator(DataSourceLevel dataSourceLevel) throws NoDataSourceObjectsException	{
		List<DataSourceObject> dataSourceObjects = dataSourceLevel.getDataSourceObjects();
		Iterator<DataSourceObject> iterator = dataSourceObjects!=null?dataSourceObjects.iterator():(new ArrayList<DataSourceObject>()).iterator();
		if (!iterator.hasNext())
			throw new NoDataSourceObjectsException();
		return iterator;
	}
	
	public static String convertSpecialCharacters(String urlFilename)	{
		CharSequence charSeq = "&amp;";
		String replaceWith = "%26";
		
		urlFilename = convertSpecialCharacters(urlFilename, charSeq, replaceWith);
		charSeq = " ";
		replaceWith="+";
		
		return convertSpecialCharacters(urlFilename, charSeq, replaceWith);
	}
	
	public static String convertSpecialCharacters(String urlFilename, CharSequence charSeq, String replaceWith)	{
		while (urlFilename!=null && urlFilename.contains(charSeq))	{
			int start = urlFilename.indexOf(charSeq.toString());
			urlFilename = urlFilename.substring(0, start) + replaceWith + urlFilename.substring(start + charSeq.length());
		}
		return urlFilename;
	}
	
	private static String removeFirstSlash(String urlFilename)	{
		if (urlFilename.substring(0, 1).equals("/"))
			return urlFilename.substring(1);
		return urlFilename;
	}
	
	public static String generateURLText(DataSourceLevel dataSourceLevel, DataItem dataItem)	{
		return generateURLText(dataSourceLevel, getFirstUrl(dataItem), getFirstConcat(dataItem));
	}
	
	public static String generateURLText(DataSourceLevel dataSourceLevel, String urlFilename, Boolean concat) 	{
		String urlText = dataSourceLevel.getDataSourceURL();
		String fullUrlText;
		if (urlFilename!=null)	{		// For Concat urls
			urlFilename = convertSpecialCharacters(urlFilename);
			urlFilename = removeFirstSlash(urlFilename);
			if (!concat)	{
				int slashIndex = urlText.lastIndexOf('/');
				String urlWithoutFilename;
				urlWithoutFilename = urlText.substring(0, slashIndex);
				fullUrlText = urlWithoutFilename + "/" + urlFilename;					
			}	else	
				fullUrlText = urlText + urlFilename;					
			
		}
		else	{
			fullUrlText = urlText;	
		}
		return fullUrlText;
	}
	
	private void getInternetReader(DataSourceLevel dataSourceLevel, String urlFilename, Boolean concat) throws NotMarkedForExecutionException	{
		if (!dataSourceLevel.getDataSourceExecution())	
			throw new NotMarkedForExecutionException();
		try	{
			if (fileURLReplacement==null)	{
				String urlText = generateURLText(dataSourceLevel, urlFilename, concat);
				URL url = new URL(urlText);
		        URLConnection yc = url.openConnection();
		        in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
		        System.out.println(urlText);
			} else	{
				String curDir = System.getProperty("user.dir");
				System.out.println(curDir);
				File myFile = new File(fileURLReplacement);
				FileInputStream myInputStream = new FileInputStream(myFile);
		        in = new BufferedReader(new InputStreamReader(myInputStream));
			}
		} catch (Exception e)	{
			System.out.println("getInternetReader() Failed!");
		}
	}	
	
	private static String getFirstUrl(DataItem dataItem)	{
		if (dataItem!=null)	
			return dataItem.getFirstUrl();
		return null;
	}
	private static Boolean getFirstConcat(DataItem dataItem)	{
		if (dataItem!=null)	
			return dataItem.getFirstConcat();
		return null;
	}
}
